package com.example.vaultmysql.service;

import com.bettercloud.vault.Vault;
import com.bettercloud.vault.VaultConfig;
import com.bettercloud.vault.VaultException;
import com.bettercloud.vault.response.LogicalResponse;
import com.example.vaultmysql.dto.DatabaseCredentials;
import com.example.vaultmysql.dto.VaultConnectionTestResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.util.Map;

/**
 * Vault服务类
 * 负责与HashiCorp Vault集成，管理数据库凭证
 * 
 * @author System
 * @version 1.0.0
 */
@Slf4j
@Service
public class VaultService {

    @Value("${vault.uri:http://localhost:8200}")
    private String vaultUri;

    @Value("${vault.token:}")
    private String vaultToken;

    @Value("${vault.namespace:}")
    private String vaultNamespace;

    private Vault vault;

    /**
     * 初始化Vault客户端
     */
    public void initializeVault() throws VaultException {
        try {
            VaultConfig config = new VaultConfig()
                    .address(vaultUri)
                    .token(vaultToken);
            
            if (vaultNamespace != null && !vaultNamespace.trim().isEmpty()) {
                config.nameSpace(vaultNamespace);
            }
            
            this.vault = new Vault(config);
            log.info("Vault客户端初始化成功: {}", vaultUri);
        } catch (VaultException e) {
            log.error("Vault客户端初始化失败: {}", e.getMessage());
            throw e;
        }
    }

    /**
     * 初始化Vault客户端（自定义配置）
     */
    public void initializeVault(String uri, String token, String namespace) throws VaultException {
        try {
            VaultConfig config = new VaultConfig()
                    .address(uri)
                    .token(token);
            
            if (namespace != null && !namespace.trim().isEmpty()) {
                config.nameSpace(namespace);
            }
            
            this.vault = new Vault(config);
            log.info("Vault客户端初始化成功: {}", uri);
        } catch (VaultException e) {
            log.error("Vault客户端初始化失败: {}", e.getMessage());
            throw e;
        }
    }

    /**
     * 测试Vault连接
     */
    public VaultConnectionTestResult testConnection() {
        return testConnection(vaultUri, vaultToken, vaultNamespace);
    }

    /**
     * 测试Vault连接（自定义配置）
     */
    public VaultConnectionTestResult testConnection(String uri, String token, String namespace) {
        long startTime = System.currentTimeMillis();
        
        try {
            VaultConfig config = new VaultConfig()
                    .address(uri)
                    .token(token);
            
            if (namespace != null && !namespace.trim().isEmpty()) {
                config.nameSpace(namespace);
            }
            
            Vault testVault = new Vault(config);
            
            // 尝试读取系统健康状态
            testVault.sys().health();
            
            long latency = System.currentTimeMillis() - startTime;
            
            return VaultConnectionTestResult.builder()
                    .success(true)
                    .message("连接成功")
                    .latency(latency)
                    .build();
                    
        } catch (VaultException e) {
            long latency = System.currentTimeMillis() - startTime;
            log.error("Vault连接测试失败: {}", e.getMessage());
            
            return VaultConnectionTestResult.builder()
                    .success(false)
                    .message("连接失败: " + e.getMessage())
                    .latency(latency)
                    .build();
        }
    }

    /**
     * 从Vault获取数据库凭证（带缓存）
     */
    @Cacheable(value = "database-credentials", key = "#vaultPath")
    public DatabaseCredentials getDatabaseCredentials(String vaultPath) throws VaultException {
        if (vault == null) {
            initializeVault();
        }
        
        try {
            log.debug("从Vault获取数据库凭证: {}", vaultPath);
            
            LogicalResponse response = vault.logical().read(vaultPath);
            
            if (response == null || response.getData() == null) {
                throw new VaultException("未找到指定路径的凭证: " + vaultPath);
            }
            
            Map<String, String> data = response.getData();
            String username = data.get("username");
            String password = data.get("password");
            
            if (username == null || password == null) {
                throw new VaultException("凭证数据不完整，缺少username或password");
            }
            
            log.debug("成功获取数据库凭证，用户名: {}", username);
            
            return DatabaseCredentials.builder()
                    .username(username)
                    .password(password)
                    .vaultPath(vaultPath)
                    .build();
                    
        } catch (VaultException e) {
            log.error("获取数据库凭证失败: path={}, error={}", vaultPath, e.getMessage());
            throw e;
        }
    }

    /**
     * 向Vault写入数据库凭证
     */
    public void storeDatabaseCredentials(String vaultPath, String username, String password) throws VaultException {
        if (vault == null) {
            initializeVault();
        }
        
        try {
            Map<String, Object> secrets = Map.of(
                    "username", username,
                    "password", password
            );
            
            vault.logical().write(vaultPath, secrets);
            log.info("成功存储数据库凭证到Vault: {}", vaultPath);
            
        } catch (VaultException e) {
            log.error("存储数据库凭证失败: path={}, error={}", vaultPath, e.getMessage());
            throw e;
        }
    }

    /**
     * 检查Vault路径是否存在
     */
    public boolean pathExists(String vaultPath) {
        if (vault == null) {
            try {
                initializeVault();
            } catch (VaultException e) {
                log.error("初始化Vault失败: {}", e.getMessage());
                return false;
            }
        }
        
        try {
            LogicalResponse response = vault.logical().read(vaultPath);
            return response != null && response.getData() != null;
        } catch (VaultException e) {
            log.debug("检查Vault路径失败: path={}, error={}", vaultPath, e.getMessage());
            return false;
        }
    }

    /**
     * 删除Vault中的凭证
     */
    public void deleteCredentials(String vaultPath) throws VaultException {
        if (vault == null) {
            initializeVault();
        }
        
        try {
            vault.logical().delete(vaultPath);
            log.info("成功删除Vault凭证: {}", vaultPath);
        } catch (VaultException e) {
            log.error("删除Vault凭证失败: path={}, error={}", vaultPath, e.getMessage());
            throw e;
        }
    }

    /**
     * 获取Vault健康状态
     */
    public boolean isHealthy() {
        if (vault == null) {
            return false;
        }
        
        try {
            vault.sys().health();
            return true;
        } catch (VaultException e) {
            log.warn("Vault健康检查失败: {}", e.getMessage());
            return false;
        }
    }
}